package org.daymr.sglandroid01;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

import android.opengl.GLES20;

/**
 * 正方形
 * @author Ben
 * @date 2015年1月1日 下午11:45:23
 */
public class Square {
	/**自定义渲染管线程序id */
	int mProgram;
	/**总变换矩阵引用*/
	int muMVPMatrixHandle;
	/**顶点位置属性引用id*/
	int maPositionHandle;
	/**顶点颜色属性引用id */
	int maColorHandle;
	
	/**顶点着色器代码脚本*/
	String mVertexShader;
	/**片元着色器代码脚本*/
	String mFragmentShader;
	
	/**顶点坐标数据缓冲*/
	FloatBuffer mVertexBuffer1,mVertexBuffer2,mVertexBuffer3;
	/**顶点颜色数据缓冲*/
	FloatBuffer mColorBuffer1,mColorBuffer2,mColorBuffer3;
	/**顶点索引数据缓冲*/
	ByteBuffer mIndexBuffer1,mIndexBuffer2,mIndexBuffer3;
	
	/**顶点个数*/
	int mCount1,mCount2,mCount3;
	
	/**定义边长*/
	public static float STEP = 0.8f;
	
	public Square(MyView mv){
		initVertexData();
		initShader(mv);
	}
	
	/**
	 * 初始化顶点数据[养成使用同一的绘画顺序的习惯，逆时针或者顺时针]
	 */
	private void initVertexData(){
		/****************GLES20.GL_TRIANGLES**********************/
		/**
		 * 这种方式绘制，顶点不重复，所以会造成数据有很多的重复，浪费资源。
		 */
		//顶点数组
		float[] mVertex1 = new float[]{//x,y,z
				-STEP,STEP,0,  //0
				-STEP,-STEP,0, //1
				STEP,-STEP,0,  //2
				
				-STEP,STEP,0, //3(0)
				STEP,-STEP,0, //4(2)
				STEP,STEP,0 //5(3)
		};
		//顶点数
		mCount1 = mVertex1.length/3;
		//顶点数组缓冲
		mVertexBuffer1 = BufferUtils.getFloatBuffer(mVertex1.length*4);
		mVertexBuffer1.put(mVertex1).position(0);
		
		//顶点索引数组
		byte[] mIndex1 = new byte[mCount1];
		for(int i=0;i<mCount1;i++){
			mIndex1[i] = (byte) i;
		}
		/**
		 * FIXME:这种索引方式是错误的，具体原因没弄明白，但我猜测是
		 * 上面给顶点数组赋的值造成的。若是定义正方形的四个顶点，再
		 * 使用这种方式就是正确的，见第二种方式绘制。
		 */
//		byte[] mIndex1 = new byte[]{
//				0,1,2,
//				0,2,3
//		};
		//顶点索引缓冲
		mIndexBuffer1 = BufferUtils.getByteBuffer(mIndex1.length);
		mIndexBuffer1.put(mIndex1).position(0);
		
		//顶点颜色数组
		float[] mColor1 = new float[]{//r,g,b,a
				1f,0f,0f,1f,
				0f,1f,0f,1f,
				0f,0f,1f,1f,
				
				1f,0f,0f,1f,
				0f,0f,1f,1f,
				0f,1f,0f,1f
		};
		//顶点颜色数组缓冲
		mColorBuffer1 = BufferUtils.getFloatBuffer(mColor1.length*4);
		mColorBuffer1.put(mColor1).position(0);
		
		/****************GLES20.GL_TRIANGLE_STRIP**********************/
		/**
		 * 如果当前顶点n是奇数：
		 *	组成三角形的顶点排列顺序：T = [n-1, n-2, n]
		 * 如果当前顶点n是偶数：
		 * 组成三角形的顶点排列顺序：T = [n-2,n-1,n]
		 * 绘画顺序为：0,1,2,  2,1,3
		 */
		float[] mVertex2 = new float[]{//x,y,z
				-STEP,STEP,0, //0
				-STEP,-STEP,0, //1
				STEP,STEP,0, //2
				STEP,-STEP,0 //3
		};
		mCount2 = mVertex2.length/3;
		mVertexBuffer2 = BufferUtils.getFloatBuffer(mVertex2.length*4);
		mVertexBuffer2.put(mVertex2).position(0);
		
		//顶点索引数组
		byte[] mIndex2 = new byte[mCount2];
		for(int i=0;i<mCount2;i++){
			mIndex2[i]=(byte)i;
		}
		//采用GL_TRIANGLES方式绘制，mCount2=6
//		byte[] mIndex2 = new byte[]{
//				0,1,2,
//				2,1,3
//		};
		//顶点索引缓冲
		mIndexBuffer2 = BufferUtils.getByteBuffer(mIndex2.length);
		mIndexBuffer2.put(mIndex2).position(0);
		
		float[] mColor2 = new float[]{//r,g,b,a
				1f,0f,0f,1f,
				1f,0f,0f,1f,
				0f,0f,1f,1f,
				0f,0f,1f,1f
		};
		mColorBuffer2 = BufferUtils.getFloatBuffer(mColor2.length*4);
		mColorBuffer2.put(mColor2).position(0);
		
		/****************GL_TRIANGLE_FAN**********************/
		/**
		 * 0,1,2,  0,2,3,  0,3,4,  0,4,5(1)  
		 */
		float[] mVertex3 = new float[]{//x,y,z
				0,0,0, //0
				-STEP,-STEP,0, //1
				STEP,-STEP,0, //2
				STEP,STEP,0, //3
				-STEP,STEP,0, //4
				-STEP,-STEP,0 //5(1)
		};
		mCount3 = mVertex3.length/3;
		mVertexBuffer3 = BufferUtils.getFloatBuffer(mVertex3.length*4);
		mVertexBuffer3.put(mVertex3).position(0);
		
		//顶点索引数组，采用的是GL_TRIANGLE_FAN方式来绘制。一般顶点很多时候，用这种索引，方便，不会出错。
//		byte[] mIndex3 = new byte[mCount3];
//		for(int i=0;i<mCount3;i++){
//			mIndex3[i]=(byte)i;
//		}
		//采用的是GL_TRIANGLE_FAN方式来绘制。[第五个点就是第一个点]
		byte[] mIndex3 = new byte[]{
				0,1,2,3,4,1
		};
		//下面这种索引mCount = 12,采用的是GL_TRIANGLES方式绘制
//		byte[] mIndex3= new byte[]{
//				0,1,2,  0,2,3,  0,3,4,  0,4,1
//		};
		//顶点索引缓冲
		mIndexBuffer3 = BufferUtils.getByteBuffer(mIndex3.length);
		mIndexBuffer3.put(mIndex3).position(0);
		
		float[] mColor3 = new float[]{//r,g,b,a
				1f,1f,1f,1f,
				1f,1f,0f,1f,
				1f,0f,0f,1f,
				0f,1f,0f,1f,
				0f,0f,1f,1f,
				1f,1f,0f,1f
		};
		mColorBuffer3 = BufferUtils.getFloatBuffer(mColor3.length*4);
		mColorBuffer3.put(mColor3).position(0);
	}
	
	/**
	 * 创建并初始化着色器
	 * @param mv
	 */
	private void initShader(MyView mv){
		//读取顶点着色器代码脚本
		mVertexShader = ShaderUtils.loadFromAssetsFile("vertex.sh", mv.getResources());
		//读取片元着色器代码脚本
		mFragmentShader = ShaderUtils.loadFromAssetsFile("frag.sh", mv.getResources());
		
		//创建着色器程序
		mProgram = ShaderUtils.createProgram(mVertexShader, mFragmentShader);
		
		//获取总变换矩阵引用
		muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
		//获取顶点位置属性引用
		maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
		//获取顶点颜色属性引用
		maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
	}

	/**
	 * 绘画
	 */
	public void draw(int flag,boolean useIBO){
		//使用某套着色器程序
		GLES20.glUseProgram(mProgram);
		//将最终变换矩阵传入着色器程序
		GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, 
				MatrixUtils.getFinalMatrix(), 0);
		//允许顶点位置数据数组
		GLES20.glEnableVertexAttribArray(maPositionHandle);
		GLES20.glEnableVertexAttribArray(maColorHandle);
		
		if(flag==1){//GLES20.GL_TRIANGLES
			//将顶点数据传入着色器程序
			GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
					false, 3*4, mVertexBuffer1);
			//将颜色数据传入着色器程序
			GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT,
					false, 4*4, mColorBuffer1);
			//绘画
			if(useIBO)//使用顶点索引绘画，type必须为GL_UNSIGNED_BYTE或者GL_UNSIGNED_SHORT。
				GLES20.glDrawElements(GLES20.GL_TRIANGLES, mCount1, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer1);
			else
				GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mCount1);
			
		}else if(flag==2){//GL_TRIANGLE_STRIP
			//将顶点数据传入着色器程序
			GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
					false, 3*4, mVertexBuffer2);
			//将颜色数据传入着色器程序
			GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT,
					false, 4*4, mColorBuffer2);
			//绘画
			if(useIBO)//使用顶点索引绘画
				GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, mCount2, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer2);
			else
				GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mCount2);
		}else if(flag==3){//GL_TRIANGLE_FAN
			//将顶点数据传入着色器程序
			GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
					false, 3*4, mVertexBuffer3);
			//将颜色数据传入着色器程序
			GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT,
					false, 4*4, mColorBuffer3);
			//绘画
			if(useIBO)//使用顶点索引绘画
				GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, mCount3, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer3);
			else
				GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, mCount3);
		}
	}
	
}
